﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.VisualStudio.OLE.Interop;
using Microsoft.VsTemplateDesigner;
using Microsoft.VisualStudio.Shell.Interop;
using System.Collections;
using rfc1459.PS3Project.EditorIntegration;

namespace rfc1459.PS3Project.AdditionalVSHelpers
{
    public partial class VsDesignerControl : UserControl, IViewModel, IDataErrorInfo, INotifyPropertyChanged
    {
        private IOleUndoManager _undoManager;
        private EditorPane _editorPane;
        private VSTemplate _vstemplateModel = null;
        private long _dirtyTime;

        public VsDesignerControl()
        {
            InitializeComponent();
        }

        public VsDesignerControl(EditorPane editorpane, IOleUndoManager undomanager)
        {
            _editorPane = editorpane;
            _undoManager = undomanager;

            InitializeComponent();
        }

        /*
        private void treeContent_Loaded(object sender, RoutedEventArgs e)
        {
            var treeView = sender as TreeView;
            if (treeView != null)
            {
                // make sure that any top-level items that contain other items are expanded
                foreach (object item in treeView.Items)
                {
                    TreeViewItem treeItem = treeView.ItemContainerGenerator.ContainerFromItem(item) as TreeViewItem;
                    treeItem.IsExpanded = true;
                }
            }
        }
        */

        /*
        private void treeContent_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            var treeView = sender as TreeView;
            if ((_viewModel != null) && (treeView != null))
            {
                // pass Selection events along to the view model so that the Properties window is updated
                _viewModel.OnSelectChanged(treeView.SelectedItem);
            }
        }
        */

        /*
        private void cbLocation_Loaded(object sender, RoutedEventArgs e)
        {
            var comboBox = sender as ComboBox;
            if (!_viewModel.IsLocationFieldSpecified)
            {
                // don't show selection in combobox if there was no data in file
                comboBox.SelectedIndex = -1;
            }
        }
        */

        #region Properties

        /// <summary>
        /// Property indicating if there is a pending change in the underlying text buffer
        /// that needs to be reflected in the ViewModel.
        /// 
        /// Used by DoIdle to determine if we need to sync.
        /// </summary>
        bool BufferDirty
        {
            get;
            set;
        }

        public virtual bool IsEditorParsing
        {
            get { return false; }
            set { }
        }

        public IOleUndoManager UndoManager
        {
            get { return _undoManager; }
        }

        public virtual string FullPath
        {
            get { return ""; }
        }

        #endregion Properties

        #region IViewModel implementation

        public Microsoft.VsTemplateDesigner.VSTemplateTemplateData TemplateData
        {
            get
            {
                return _vstemplateModel.TemplateData;
            }
        }

        public Microsoft.VsTemplateDesigner.VSTemplateTemplateContent TemplateContent
        {
            get
            {
                return _vstemplateModel.TemplateContent;
            }
        }

        public string Description
        {
            get
            {
                if (!IsDescriptionEnabled)
                {
                    return _vstemplateModel.TemplateData.Description.Package + " " + _vstemplateModel.TemplateData.Description.ID;
                }
                return _vstemplateModel.TemplateData.Description.Value;
            }
            set
            {
                if (_vstemplateModel.TemplateData.Description.Value != value)
                {
                    _vstemplateModel.TemplateData.Description.Value = value;
                    DesignerDirty = true;
                    NotifyPropertyChanged("Description");
                }
            }
        }

        public string Icon
        {
            get
            {
                if (!IsIconEnabled)
                {
                    return _vstemplateModel.TemplateData.Icon.Package + " " + _vstemplateModel.TemplateData.Icon.ID;
                }
                return _vstemplateModel.TemplateData.Icon.Value;
            }
            set
            {
                if (_vstemplateModel.TemplateData.Icon.Value != value)
                {
                    _vstemplateModel.TemplateData.Icon.Value = value;
                    DesignerDirty = true;
                    NotifyPropertyChanged("Icon");
                }
            }
        }

        public string ProjectType
        {
            get
            {
                return _vstemplateModel.TemplateData.ProjectType;
            }
            set
            {
                if (_vstemplateModel.TemplateData.ProjectType != value)
                {
                    _vstemplateModel.TemplateData.ProjectType = value;
                    DesignerDirty = true;
                    NotifyPropertyChanged("ProjectType");
                }
            }
        }

        public string ProjectSubType
        {
            get
            {
                return _vstemplateModel.TemplateData.ProjectSubType;
            }
            set
            {
                if (_vstemplateModel.TemplateData.ProjectSubType != value)
                {
                    _vstemplateModel.TemplateData.ProjectSubType = value;
                    DesignerDirty = true;
                    NotifyPropertyChanged("ProjectSubType");
                }
            }
        }

        public string DefaultName
        {
            get
            {
                return _vstemplateModel.TemplateData.DefaultName;
            }
            set
            {
                if (_vstemplateModel.TemplateData.DefaultName != value)
                {
                    _vstemplateModel.TemplateData.DefaultName = value;
                    DesignerDirty = true;
                    NotifyPropertyChanged("DefaultName");
                }
            }
        }

        public string TemplateID
        {
            get
            {
                return _vstemplateModel.TemplateData.TemplateID;
            }
            set
            {
                if (_vstemplateModel.TemplateData.TemplateID != value)
                {
                    _vstemplateModel.TemplateData.TemplateID = value;
                    DesignerDirty = true;
                    NotifyPropertyChanged("TemplateID");
                }
            }
        }

        public string GroupID
        {
            get
            {
                return _vstemplateModel.TemplateData.TemplateGroupID;
            }
            set
            {
                if (_vstemplateModel.TemplateData.TemplateGroupID != value)
                {
                    _vstemplateModel.TemplateData.TemplateGroupID = value;
                    DesignerDirty = true;
                    NotifyPropertyChanged("TemplateGroupID");
                }
            }
        }

        public string SortOrder
        {
            get
            {
                return _vstemplateModel.TemplateData.SortOrder;
            }
            set
            {
                if (_vstemplateModel.TemplateData.SortOrder != value)
                {
                    _vstemplateModel.TemplateData.SortOrder = value;
                    DesignerDirty = true;
                    NotifyPropertyChanged("SortOrder");
                }
            }
        }

        public Microsoft.VsTemplateDesigner.VSTemplateTemplateDataLocationField LocationField
        {
            get
            {
                return _vstemplateModel.TemplateData.LocationField;
            }
            set
            {
                if (_vstemplateModel.TemplateData.LocationField != value)
                {
                    // if we don't make sure the XML model knows this value is specified,
                    // it won't save it (and it will get reset the next time we read the model)
                    _vstemplateModel.TemplateData.LocationFieldSpecified = true;
                    _vstemplateModel.TemplateData.LocationField = value;
                    DesignerDirty = true;
                    NotifyPropertyChanged("LocationField");
                }
            }
        }

        public string LocationFieldMRUPrefix
        {
            get
            {
                return _vstemplateModel.TemplateData.LocationFieldMRUPrefix;
            }
            set
            {
                if (_vstemplateModel.TemplateData.LocationFieldMRUPrefix != value)
                {
                    _vstemplateModel.TemplateData.LocationFieldMRUPrefix = value;
                    DesignerDirty = true;
                    NotifyPropertyChanged("LocationFieldMRUPrefix");
                }
            }
        }

        public string PreviewImage
        {
            get
            {
                return _vstemplateModel.TemplateData.PreviewImage;
            }
            set
            {
                if (_vstemplateModel.TemplateData.PreviewImage != value)
                {
                    _vstemplateModel.TemplateData.PreviewImage = value;
                    DesignerDirty = true;
                    NotifyPropertyChanged("PreviewImage");
                }
            }
        }

        public string WizardAssembly
        {
            get
            {
                if ((_vstemplateModel.WizardExtension != null) && (_vstemplateModel.WizardExtension.Count() == 1) && (_vstemplateModel.WizardExtension[0].Assembly.Count() == 1))
                {
                    return _vstemplateModel.WizardExtension[0].Assembly[0] as string;
                }
                return null;
            }
            set
            {
                // intentionally not implemented until the correct behavior is determined
            }
        }

        public string WizardClassName
        {
            get
            {
                if ((_vstemplateModel.WizardExtension != null) && (_vstemplateModel.WizardExtension.Count() == 1) && (_vstemplateModel.WizardExtension[0].FullClassName.Count() == 1))
                {
                    return _vstemplateModel.WizardExtension[0].FullClassName[0] as string;
                }
                return null;
            }
            set
            {
                // intentionally not implemented until the correct behavior is determined
            }
        }

        public string WizardData
        {
            get
            {
                string result = "";
                if (_vstemplateModel.WizardData == null)
                {
                    return result;
                }
                foreach (var wizData in _vstemplateModel.WizardData)
                {
                    foreach (var xmlItem in wizData.Any)
                    {
                        result += xmlItem;
                    }
                }
                return result;
            }
            set
            {
                // intentionally not implemented until the correct behavior is determined
            }
        }

        public bool ProvideDefaultName
        {
            get
            {
                return _vstemplateModel.TemplateData.ProvideDefaultName;
            }
            set
            {
                if (_vstemplateModel.TemplateData.ProvideDefaultName != value)
                {
                    // if we don't make sure the XML model knows this value is specified,
                    // it won't save it (and it will get reset the next time we read the model)
                    _vstemplateModel.TemplateData.ProvideDefaultNameSpecified = true;
                    _vstemplateModel.TemplateData.ProvideDefaultName = value;
                    DesignerDirty = true;
                    NotifyPropertyChanged("ProvideDefaultName");
                }
            }
        }

        public bool CreateNewFolder
        {
            get
            {
                return _vstemplateModel.TemplateData.CreateNewFolder;
            }
            set
            {
                if (_vstemplateModel.TemplateData.CreateNewFolder != value)
                {
                    // if we don't make sure the XML model knows this value is specified,
                    // it won't save it (and it will get reset the next time we read the model)
                    _vstemplateModel.TemplateData.CreateNewFolderSpecified = true;
                    _vstemplateModel.TemplateData.CreateNewFolder = value;
                    DesignerDirty = true;
                    NotifyPropertyChanged("CreateNewFolder");
                }
            }
        }

        public bool PromptForSaveOnCreation
        {
            get
            {
                return _vstemplateModel.TemplateData.PromptForSaveOnCreation;
            }
            set
            {
                if (_vstemplateModel.TemplateData.PromptForSaveOnCreation != value)
                {
                    // if we don't make sure the XML model knows this value is specified,
                    // it won't save it (and it will get reset the next time we read the model)
                    _vstemplateModel.TemplateData.PromptForSaveOnCreationSpecified = true;
                    _vstemplateModel.TemplateData.PromptForSaveOnCreation = value;
                    DesignerDirty = true;
                    NotifyPropertyChanged("PromptForSaveOnCreation");
                }
            }
        }

        public bool Hidden
        {
            get
            {
                return _vstemplateModel.TemplateData.Hidden;
            }
            set
            {
                if (_vstemplateModel.TemplateData.Hidden != value)
                {
                    // if we don't make sure the XML model knows this value is specified,
                    // it won't save it (and it will get reset the next time we read the model)
                    _vstemplateModel.TemplateData.HiddenSpecified = true;
                    _vstemplateModel.TemplateData.Hidden = value;
                    DesignerDirty = true;
                    NotifyPropertyChanged("Hidden");
                }
            }
        }

        public bool SupportsMasterPage
        {
            get
            {
                return _vstemplateModel.TemplateData.SupportsMasterPage;
            }
            set
            {
                if (_vstemplateModel.TemplateData.SupportsMasterPage != value)
                {
                    // if we don't make sure the XML model knows this value is specified,
                    // it won't save it (and it will get reset the next time we read the model)
                    _vstemplateModel.TemplateData.SupportsMasterPageSpecified = true;
                    _vstemplateModel.TemplateData.SupportsMasterPage = value;
                    DesignerDirty = true;
                    NotifyPropertyChanged("SupportsMasterPage");
                }
            }
        }

        public bool SupportsCodeSeparation
        {
            get
            {
                return _vstemplateModel.TemplateData.SupportsCodeSeparation;
            }
            set
            {
                if (_vstemplateModel.TemplateData.SupportsCodeSeparation != value)
                {
                    // if we don't make sure the XML model knows this value is specified,
                    // it won't save it (and it will get reset the next time we read the model)
                    _vstemplateModel.TemplateData.SupportsCodeSeparationSpecified = true;
                    _vstemplateModel.TemplateData.SupportsCodeSeparation = value;
                    DesignerDirty = true;
                    NotifyPropertyChanged("SupportsCodeSeparation");
                }
            }
        }

        public bool SupportsLanguageDropDown
        {
            get
            {
                return _vstemplateModel.TemplateData.SupportsLanguageDropDown;
            }
            set
            {
                if (_vstemplateModel.TemplateData.SupportsLanguageDropDown != value)
                {
                    // if we don't make sure the XML model knows this value is specified,
                    // it won't save it (and it will get reset the next time we read the model)
                    _vstemplateModel.TemplateData.SupportsLanguageDropDownSpecified = true;
                    _vstemplateModel.TemplateData.SupportsLanguageDropDown = value;
                    DesignerDirty = true;
                    NotifyPropertyChanged("SupportsLanguageDropDown");
                }
            }
        }

        public bool DesignerDirty
        {
            get;
            set;
        }

        public bool IsNameEnabled
        {
            get
            {
                // only enable if not associated with a package (guid)
                return string.IsNullOrEmpty(_vstemplateModel.TemplateData.Name.Package);
            }
        }

        public bool IsDescriptionEnabled
        {
            get
            {
                // only enable if not associated with a package (guid)
                return string.IsNullOrEmpty(_vstemplateModel.TemplateData.Description.Package);
            }
        }

        public bool IsIconEnabled
        {
            get
            {
                // only enable if not associated with a package (guid)
                return string.IsNullOrEmpty(_vstemplateModel.TemplateData.Icon.Package);
            }
        }

        public bool IsLocationFieldSpecified
        {
            get
            {
                return _vstemplateModel.TemplateData.LocationFieldSpecified;
            }
        }

        event EventHandler IViewModel.ViewModelChanged
        {
            add { throw new NotImplementedException(); }
            remove { throw new NotImplementedException(); }
        }

        void IViewModel.DoIdle()
        {
            if (!this.Focused)
                return;

            if (BufferDirty || DesignerDirty)
            {
                int delay = 100;

                if ((Environment.TickCount - _dirtyTime) > delay)
                {
                    // Must not try and sync while XML editor is parsing otherwise we just confuse matters.
                    if (IsEditorParsing)
                    {
                        _dirtyTime = System.Environment.TickCount;
                        return;
                    }

                    // If there is contention, give the preference to the designer.
                    if (DesignerDirty)
                    {
                        SaveModel();
                        //We don't do any merging, so just overwrite whatever was in the buffer.
                        BufferDirty = false;
                    }
                    else if (BufferDirty)
                    {
                        LoadModel();
                    }
                }
            }
        }

        /// <summary>
        /// Load the model from the underlying text buffer.
        /// </summary>
        public virtual void LoadModel()
        {
        }

        /// <summary>
        /// This method is called when it is time to save the designer values to the
        /// underlying buffer.
        /// </summary>
        /// <param name="undoEntry"></param>
        public virtual void SaveModel()
        {
        }

        public void Close()
        {
            // Unhook any events
        }

        public void OnSelectChanged(object p)
        {
        }

        #endregion IViewModel implementation

        #region IDataErrorInfo implementation

        public string Error
        {
            get
            {
                throw new NotImplementedException();
            }
        }

        public string this[string columnName]
        {
            get { throw new NotImplementedException(); }
        }

        #endregion IDataErrorInfo implementation

        #region INotifyPropertyChanged implementation

        public event PropertyChangedEventHandler PropertyChanged;

        protected void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        #endregion INotifyPropertyChanged implementation
    }
}
